﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Windows.Automation;
using System.Threading;
using System.Globalization;
using Wiyan.Code.PowerMSNRobotLibrary.Manager;

namespace Wiyan.Code.PowerMSNRobotLibrary.Utility
{
    public interface IRemoteAssistanceHelper
    {
        ErrorCode GenerateRATicket(string password, ref string path);

        ErrorCode StopRASession();
        ErrorCode Allow();

        ErrorCode ApplyAutomationConfiguration();
    }

    public class VistaRemoteAssistanceHelper : IRemoteAssistanceHelper, IDisposable
    {
        bool AutomationSupported { get { return false; } }
        RobotManager.ReplyMessageDelay _messageReporter = null;
        Process msra = null;

        public RobotManager.ReplyMessageDelay MessageReporter
        {
            get
            {
                return _messageReporter;
            }
            set
            {
                _messageReporter = value;
            }
        }

        public VistaRemoteAssistanceHelper(RobotManager.ReplyMessageDelay messageReporter)
        {
            _messageReporter = messageReporter;
        }

        public ErrorCode GenerateRATicket(string password, ref string path)
        {
            // Build temp path
            if (string.IsNullOrEmpty(path) == true)
            {
                path = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".msrcincident";
            }
            
            // Delete file first
            if (File.Exists(path) == true)
            {
                File.Delete(path);
            }

            msra = new Process();
            msra.StartInfo.FileName = "msra.exe";
            msra.StartInfo.Arguments = string.Format("/saveasfile {0} {1}", path, password);

            bool result = msra.Start();
            Thread.Sleep(1000);
            return result == true ? ErrorCode.Success : ErrorCode.Error;
        }

        public ErrorCode KillByForce()
        {
            Process[] processes = Process.GetProcessesByName("msra");
            if (processes != null && processes.Length == 1)
            {
                processes[0].Kill();
                return ErrorCode.MsraProcessKilled;
            }

            return ErrorCode.Success;
        }

        public ErrorCode ApplyAutomationConfiguration()
        {
            return ErrorCode.MSRAAUTONOTSUPPORTEDAUTOCONFIG;
        }

        private void OutputAllChild(AutomationElement e)
        {
            AutomationElementCollection childElements = e.FindAll(TreeScope.Children, Condition.TrueCondition);
            Debug.WriteLine(string.Format("Print all children information for {0}", e.GetCurrentPropertyValue(AutomationElement.NameProperty).ToString()));
            foreach (AutomationElement child in childElements)
            {
                OutputProperties(child);
            }
        }

        private void OutputProperties(AutomationElement e)
        {
            Debug.WriteLine(string.Format("Debug print property info for {0}:", e.GetCurrentPropertyValue(AutomationElement.NameProperty).ToString()));

            Debug.WriteLine("\t Control Type: " + e.Current.ControlType.ProgrammaticName);
            Debug.WriteLine("\t WinHandle: " + e.Current.NativeWindowHandle.ToString("x"));
        }

        public ErrorCode StopRASession()
        {
            if (this.msra != null && this.msra.MainWindowHandle != null)
            {
                AutomationElement msraElement = AutomationElement.FromHandle(this.msra.MainWindowHandle);
                if (msraElement == null)
                {
                    return ErrorCode.MsraWindowsNotFound;
                }

                WindowPattern windowsPattern = msraElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
                if (windowsPattern != null)
                {
                    windowsPattern.Close();
                }
            }

            return ErrorCode.Success;
        }

        public ErrorCode Allow()
        {
            AutomationElement msraElement = AutomationElement.FromHandle(this.msra.MainWindowHandle);
            if (msraElement == null)
            {
                return ErrorCode.MsraWindowsNotFound;
            }

#if DEBUG
            OutputProperties(msraElement);
            OutputAllChild(msraElement);
#endif
            // Retry to find allow window
            int retryCount = 10;
            AutomationElement allowElement = null;

            do
            {
                //allowElement = msraElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.NameProperty, "Windows Remote Assistance"));
                allowElement = msraElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window));

                Thread.Sleep(1000);
            } while (allowElement == null && retryCount-- <= 0);

            if (allowElement == null)
            {
                return ErrorCode.MsraAllowWindowsNotFound;
            }

#if DEBUG
            OutputProperties(allowElement);
            OutputAllChild(allowElement);
#endif
            // Find ok button, normally, the first button in the Children list is the OK button.
            AutomationElement okButton = allowElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));
            if (okButton == null)
            {
                return ErrorCode.MsraAllowWindowsOKButtonNotFound;
            }

            OutputProperties(okButton);

            InvokePattern ipClickOKButton = (InvokePattern)okButton.GetCurrentPattern(InvokePattern.Pattern);
            if (ipClickOKButton == null)
            {
                return ErrorCode.MsraOKButtonNotSupportInvokePattern;
            }
            
            // Expose exception directly, reply exception detial to msn remote admin.
            ipClickOKButton.Invoke();

            return ErrorCode.Success;
        }

        #region IDisposable Members

        public void Dispose()
        {
            //if (msra != null)
            //    msra.Dispose();
        }

        #endregion
    }
}
